package com.huawei.rbac.util;

import com.huawei.rbac.domain.TreeNode;
import lombok.experimental.UtilityClass;

import java.util.ArrayList;
import java.util.List;

/**
 * 树形结构工具类
 *
 * @author 罗华
 * @version 2021年8月10日15:01:38
 */
@UtilityClass
public class TreeUtils {

    /**
     * 根据所有树节点列表，生成含有所有树形结构的列表
     *
     * @param treeNodes 节点数据列表
     * @return
     */
    public List<TreeNode<Long>> build(List<TreeNode<Long>> treeNodes) {
        return build(treeNodes, 0L);
    }

    /**
     * 基于两层循环构建树形结构
     *
     * @param <T>
     * @param treeNodes 节点数据列表
     * @param parentId  跟节点ID
     * @return
     */
    public <E extends TreeNode<T>, T> List<E> build(List<E> treeNodes, T parentId) {
        final List<E> treeList = new ArrayList<>();
        for (E treeNode : treeNodes) {
            if (parentId.equals(treeNode.getParentId())) {
                treeList.add(treeNode);
            }

            for (E childNode : treeNodes) {
                if (childNode.getParentId().equals(treeNode.getId())) {
                    List<TreeNode<T>> children = treeNode.getChildren();
                    if (treeNode.getChildren() == null) {
                        children = new ArrayList<>();
                        treeNode.setChildren(children);
                    }
                    children.add(childNode);
                }
            }
        }
        return treeList;
    }

    /**
     * 基于递归方法构建树形结构
     *
     * @param <T>
     * @param treeNodes 节点数据列表
     * @param parentId  跟节点ID
     * @return
     */
    public <E extends TreeNode<T>, T> List<E> buildTree(List<E> treeNodes, T parentId) {
        final List<E> treeList = new ArrayList<>();
        for (E treeNode : treeNodes) {
            if (parentId.equals(treeNode.getParentId())) {
                treeList.add(treeNode);
                innerBuild(treeNodes, treeNode);
            }
        }
        return treeList;
    }

    /**
     * 从所有节点列表中查找并设置parent的所有子节点
     *
     * @param <T>
     * @param treeNodes  所有树节点列表
     * @param parentNode 父节点
     */
    private <E extends TreeNode<T>, T> void innerBuild(List<E> treeNodes, TreeNode<T> parentNode) {
        for (TreeNode<T> childNode : treeNodes) {
            if (parentNode.getId().equals(childNode.getParentId())) {
                List<TreeNode<T>> children = parentNode.getChildren();
                if (children == null) {
                    children = new ArrayList<>();
                    parentNode.setChildren(children);
                }
                children.add(childNode);
                innerBuild(treeNodes, childNode);
            }
        }
    }

}